<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>借助HTML5标签details实现折叠面板</title>
  <style>
    :root {
      --speed: 0.3s;
    }

    html {
      background: #f8f5fe;
    }

    .details-group {
      width: 500px;
      padding: 10px;
      border: 1px solid #b5b0b0;
      box-shadow: 0.2em 1em 2em -1em #d6d1e0;
      margin: 2.4em 0;
    }

    .details {
      background: #fff;
      border: 1px solid #d6d1e0;
      border-bottom: 0;
      /* border-radius: 6px; */
      list-style: none;
      box-sizing: border-box;
      overflow: hidden;
      transition: all var(--speed) ease-in-out;
    }

    .details:first-of-type {
      border-radius: 6px 6px 0 0;
    }

    .details:last-of-type {
      border-bottom: 1px solid #d6d1e0;
      border-radius: 0 0 6px 6px;
    }

    .details__summary {
      position: relative;
      display: block;
      padding: 1em;
      font-weight: 700;
      cursor: pointer;
      transition: all var(--speed) ease-in-out;
      overflow: hidden;
    }

    /* .details__summary:focus {
      outline: 2px solid #5b13ec;
    } */

    .details__summary::after {
      position: absolute;
      right: 1em;
      top: 50%;
      transform: translateY(-50%) rotate(45deg);
      content: "";
      width: 0.5em;
      height: 0.5em;
      border-right: 2px solid;
      border-bottom: 2px solid;
      transition: inherit;
    }

    .details[open] .details__summary {
      /* background: #5b13ec; */
      /* color: #fff; */
      color: #00acc1;
      border-bottom: 1px solid #d6d1e0;
    }

    .details[open] .details__summary::after {
      transform: rotate(225deg);
    }

    .details__content {
      padding: 1em;
    }
  </style>

</head>

<body>
  <h3>借助HTML5的标签，开发者可以不借助JavaScript或其他语言就实现原生的折叠面板。CSS则可以进一步美化外观，并且这一方案具有良好的性能和兼容性。</h3>

  <p>
    HTML details元素可创建一个组件，仅在被切换成展开状态时，它才会显示内含的信息。summary 元素可为该部件提供概要或者标签。
  </p>

  <p>
    展现组件通常在屏幕上使用一个小三角形，旋转（或扭转）以表示打开/关闭的状态，三角形旁边有一个标签。summary 元素的内容被用来作为展示小部件的标签。
  </p>

  <h1>Accordion with <code>&lt;details&gt;</code> element</h1>
  <p>Making the native <abbr>HTML</abbr> <code>&lt;details&gt;</code> element behave like a typical collapsible
    accordion with smooth animations.</p>

  <div class="details-group collapse">
    <details class="details" open>
      <summary class="details__summary">标题1</summary>
      <div class="details__content">
        <p>
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsa quis fuga saepe sunt
          delectus, quo assumenda dolorum officiis odit optio modi, aspernatur necessitatibus libero, itaque
          repellendus.
          Incidunt blanditiis magni velit.
        </p>

        <p>
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsa quis fuga saepe sunt delectus, quo assumenda
          dolorum officiis odit optio modi, aspernatur necessitatibus libero, itaque repellendus. Incidunt blanditiis
          magni velit.
        </p>
      </div>
    </details>

    <details class="details">
      <summary class="details__summary">标题2</summary>
      <div class="details__content">主要内容2</div>
    </details>

    <details class="details">
      <summary class="details__summary">标题3</summary>
      <div class="details__content">主要内容3</div>
    </details>


    <script>
      let accordion = true;  // 是否开启手风琴效果
      const detailsElements = document.querySelectorAll('.details');

      // 高度动画逻辑
      function setDetailsHeight(detailsEl) {
        const summary = detailsEl.querySelector('.details__summary');
        const content = detailsEl.querySelector('.details__content');

        requestAnimationFrame(() => {
          detailsEl.style.height = detailsEl.open
            ? `${summary.clientHeight + content.scrollHeight}px`
            : `${summary.clientHeight}px`;
        });
      }

      // 手风琴模式控制器
      function handleAccordionEffect(currentDetails) {
        detailsElements.forEach(details => {
          if (details !== currentDetails && details.open) {
            details.open = false;
            setDetailsHeight(details);
          }
        });
      }

      detailsElements.forEach(details => {
        if (!details.open) setDetailsHeight(details);

        details.addEventListener('toggle', () => {
          setDetailsHeight(details);
          if (accordion && details.open) {
            handleAccordionEffect(details);
          }
        });

      })

    </script>
</body>

</html>